use super::ByteResult;

macro_rules! write_byte_impl {
    (impl,$($data:ty,$func:ident),*) => {
        $(
            pub fn $func(&mut self,data:$data) -> ByteResult<()> {
                self.inner.$func(data)
            }
        )*
    };
    (trait,$($data:ty,$func:ident),*) => {
        $(
            fn $func(&mut self,data:$data) -> ByteResult<()> {
                let buf = data.to_le_bytes();
                self.write(&buf[..])?;
                Ok(())
            }
        )*
    };
}

pub struct ByteWriter<W> {
    inner:W,
}

impl<W:ByteWrite> ByteWriter<W> {
    pub fn new(inner:W) -> Self {
        Self { inner }
    }

    write_byte_impl!{
        impl,
        u8,write_from_u8,
        u16,write_from_u16,
        u32,write_from_u32,
        u64,write_from_u64,
        u128,write_from_u128
    }

    pub fn write_from_bytes(&mut self,bytes:&[u8]) -> ByteResult<()> {
        self.inner.write_from_bytes(bytes)
    }
}

pub trait ByteWrite {
    type Error;
    fn write_from_u8(&mut self, data:u8) -> ByteResult<()>;
    fn write_from_u16(&mut self, data:u16) -> ByteResult<()>;
    fn write_from_u32(&mut self, data:u32) -> ByteResult<()>;
    fn write_from_u64(&mut self, data:u64) -> ByteResult<()>;
    fn write_from_u128(&mut self, data:u128) -> ByteResult<()>;
    fn write_from_bytes(&mut self,bytes:&[u8]) -> ByteResult<()>;
}

impl<W:std::io::Write> ByteWrite for W {
    type Error = std::io::Error;
    write_byte_impl!{
        trait,
        u8,write_from_u8,
        u16,write_from_u16,
        u32,write_from_u32,
        u64,write_from_u64,
        u128,write_from_u128
    }
    fn write_from_bytes(&mut self,bytes:&[u8]) -> ByteResult<()> {
        self.write(bytes)?;
        Ok(())
    }
}